/// <reference path="_references.ts" />

//TODO:
//- destroy view
//-allow comments in config.json
//-write a better enhancer


module PrismBreak {

    export class PbApp {

        public EventManager: EventManager;
        public ViewManager: ViewManager;
        private Regionizer: RegionManager;
        private ConfigManager: ConfigManager;
        private _startTime: number;

        public constructor(configPath: string, hostEl: HTMLElement) {

            this._startTime = new Date().getTime();

            this.Enhancers();

            this.EventManager = new EventManager(this);
            this.ViewManager = new ViewManager(this);

            this.ConfigManager = new ConfigManager(this, configPath);
            this.Regionizer = new RegionManager(this, this.ConfigManager, hostEl);

            //wrong, it's now async
            //this.EventManager.Publish(PrismBreak.EventType.FrameworkInitialized);
            console.log("Pb initialized in " + (new Date().getTime() - this._startTime) + " ms");

        }

        public Initialize(): void {
            //Starting loading the regions only if all the viewmodel have been loaded
            if (!this.ConfigManager.loadingViewModelCompleted) {
                this.EventManager.Subscribe(PrismBreak.EventType[PrismBreak.EventType.ViewModelsAreLoaded], () => {
                    this.Regionizer.LoadRegions(this.ConfigManager.ConfigItems);
                });
            }
            else {
                this.Regionizer.LoadRegions(this.ConfigManager.ConfigItems);
            }
        }

        public CreateRandomToken(): string {
            //http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                    .toString(16)
                    .substring(1);
            };

            return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
                s4() + '-' + s4() + s4() + s4();

        }

        private Enhancers(): void {

            //http://stackoverflow.com/questions/690781/debugging-scripts-added-via-jquery-getscript-function
            $.extend({
                getScript: (url: string, callback: Function) => {
                    var head: HTMLHeadElement = document.getElementsByTagName("head")[0];
                    var script = document.createElement("script");
                    script.src = url;

                    // Handle Script loading
                    {
                        var done = false;

                        // Attach handlers for all browsers
                        script.onload = script.onreadystatechange = function () {
                            if (!done && (!this.readyState ||
                                this.readyState == "loaded" || this.readyState == "complete")) {
                                done = true;
                                if (callback) {
                                    callback();
                                }

                                // Handle memory leak in IE
                                script.onload = script.onreadystatechange = null;
                            }
                        };
                    }

                    head.appendChild(script);

                    // We handle everything using the script element injection
                    return undefined;
                },
            });
            //----------


            //Binary search
            (<any>Array).prototype.binarySearch = function (find, property) {

                var array = <Array<Object>>(this);

                try {
                    if (array.length && typeof array[0] == "object" && array[0].hasOwnProperty(property)) {
                        var low = this[0][property], high = this[this.length - 1][property],
                            i, comparison;
                        while (low <= high) {
                            i = Math.floor((low + high) / 2);

                            if (this[i][property] < find) {
                                low = i + 1; continue;
                            };
                            if (this[i][property] > find) {
                                high = i - 1; continue;
                            };
                            return i;
                        }
                        return null;
                    }
                    return null;
                }
                catch (e) {
                    return null;
                }
            };
        }
    }

} 
